#ifndef __event_bus_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__
#define __event_bus_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__

#include <list>
#include <mutex>
#include <memory>
#include <tuple>
#include <future>
#include <atomic>

#include "hude/base/async.hpp"
#include "hude/base/block_queue.hpp"

namespace hude
{
	namespace utils
	{
		/**********************************************************************************************
		 * @brief 通常事件总线类型定义
		 */
		template< typename _ident, typename _value = hude::any_t >
		class bus_t
		{
		public:
			typedef _ident id_t;
			typedef _value value_t;
			typedef bus_t< id_t, value_t > this_t;

			typedef std::tuple< id_t, value_t > _event_t;
			enum { emID, emDATA };

			typedef _event_t* event_t;
			typedef block_queue_t< event_t > queue_t;
			typedef std::function< void( const id_t&, value_t, bool& ) > cb_handle_t;
			typedef std::list< cb_handle_t > cb_entry_t;
			typedef typename cb_entry_t::const_iterator itr_cb_handle_t;
			typedef std::map< id_t, cb_entry_t > cb_map_t;
			typedef std::unique_lock< std::mutex > autolock_t;

		public:
			/**********************************************************************************************
			 * @brief 构造函数
			 * @param tasks: 异步任务对象，总线派发事件依赖该对象做异步回调
			 */
			bus_t( std::shared_ptr< async_t > tasks ) : tasks_( tasks ), handling_( false ) {}

			/**********************************************************************************************
			 * @brief 构造函数,异步任务对象使用全局默认的
			 */
			bus_t() : bus_t( async_t::get_default_ptr() ) {}

			/**********************************************************************************************
			 * @brief 添加事件订阅
			 * @param id: 要订阅的事件ID
			 * @param handle: 指定订阅的事件发生时的回调处理
			 * @param front: 是否插入到事件的监听队列的前面优先处理
			 * @return  返回订阅存根可用于清理本次订阅
			 */
			itr_cb_handle_t add_handle( const id_t& id, cb_handle_t handle, bool front = false );

			/**********************************************************************************************
			 * @brief 删除事件订阅
			 * @param id: 要删除订阅的事件ID
			 * @param handle: 指定订阅存根
			 */
			void del_handle( const id_t& id, itr_cb_handle_t handle );

			/**********************************************************************************************
			 * @brief 添加所有事件的预处理回调
			 * @param handle: 指定所有事件发生时的预处理回调
			 * @param front: 是否插入到事件的预处理队列的前面优先处理
			 * @return  返回预处理存根可用于清理本次预处理回调
			 */
			itr_cb_handle_t add_pre( cb_handle_t handle, bool front = false );
			
			/**********************************************************************************************
			 * @brief 删除所有事件的预处理回调
			 * @param handle: 指定预处理存根
			 */
			void del_pre( itr_cb_handle_t handle );

			/**********************************************************************************************
			 * @brief 发送事件（普通传值方式的事件数据版本）
			 * @param id: 事件的ID
			 * @param data: 事件的数据
			 */
			void event( const id_t& id, value_t data );

			/**********************************************************************************************
			 * @brief 发送事件（针对事件数据右值的优化版本）
			 * @param id: 事件的ID
			 * @param data: 事件的数据
			 */
			void event( id_t&& id, value_t&& data );

		protected:

			bool handle_event( event_t& e, cb_entry_t& entry, bool pre );

			void dispatch( event_t );
			void cb_dispatch();

		private:
            queue_t queue_;

            std::shared_ptr< hude::async_t > tasks_;
            std::mutex                       mutex_;
            cb_entry_t                       cb_pre_;
            cb_map_t                         map_;
            std::atomic_flag                 handling_;

        private:
			bus_t( const bus_t& );
			bus_t& operator=( const bus_t& );

		};
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		typename bus_t< _ident, _value >::itr_cb_handle_t bus_t< _ident, _value >::add_handle( const id_t& id, cb_handle_t handle, bool front )
		{
			autolock_t al( mutex_ );

			auto ins = map_.emplace( id, cb_entry_t{} );
			auto itr = ins.first;

			if( front )
			{
				itr->second.push_front( handle );
				return itr->second.begin();
			} else {
				itr->second.push_back( handle );
				return itr->second.rbegin().base();
			}
		}
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		void bus_t< _ident, _value >::del_handle( const id_t& id, itr_cb_handle_t handle )
		{
			autolock_t al( mutex_ );

			typename cb_map_t::iterator itr = map_.find( id );

			if( itr != map_.end() )
			{
				itr->second.erase( handle );
					
				if( itr->second.empty() )
				{
					map_.erase( itr );
				}
			}
		}
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		typename bus_t< _ident, _value >::itr_cb_handle_t bus_t< _ident, _value >::add_pre( cb_handle_t handle, bool front )
		{
			autolock_t al( mutex_ );

			if( front )
			{
				cb_pre_.push_front( handle );
				return cb_pre_.begin();
			} else {
				cb_pre_.push_back( handle );
				return ( ++cb_pre_.rbegin() ).base();
			}
		}
			
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		void bus_t< _ident, _value >::del_pre( itr_cb_handle_t handle )
		{
			cb_pre_.erase( handle );
		}
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		void bus_t< _ident, _value >::event( id_t&& id, value_t&& data )
		{
			queue_.push( event_t( new _event_t{ std::forward< id_t >( id ), std::forward< value_t >( data ) } ) );

			tasks_->add( std::bind( &this_t::cb_dispatch, this ) );
		}
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		void bus_t< _ident, _value >::event( const id_t &id, value_t data )
		{
			queue_.push( event_t( new _event_t{ id, data } ) );

			tasks_->add( std::bind( &this_t::cb_dispatch, this ) );
		}
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		bool bus_t< _ident, _value >::handle_event( event_t& e, cb_entry_t& entry, bool )
		{
			bool next = true;

			for( auto handle : entry )
			{
				handle( std::get< emID >( *e ), std::get< emDATA >( *e ), next );

				if( !next ) break;
			}

			return next;
		}
		
		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		void bus_t< _ident, _value >::dispatch( event_t e )
		{
			std::unique_ptr< _event_t > p( e );

			autolock_t al( mutex_ );

			if( handle_event( e, cb_pre_, true ) )
			{
				typename cb_map_t::iterator itr = map_.find( std::get< emID >( *e ) );

				if( itr != map_.end() )
				{
					handle_event( e, itr->second, false );
				}
			}
		}

		//----------------------------------------------------------------------------------------------
		struct exit_release_t
		{
			std::atomic_flag& f;

			exit_release_t( std::atomic_flag& v ) : f( v ) {}

			~exit_release_t() { f.clear(); }
		};

		//----------------------------------------------------------------------------------------------
		template< typename _ident, typename _value >
		void bus_t< _ident, _value >::cb_dispatch()
		{
			if( handling_.test_and_set() ) return;

			exit_release_t _( handling_ );

			auto handler = [this]( event_t& e ) { this->dispatch( e ); };

			while( queue_.consume( handler, true, std::chrono::milliseconds( 500 ) ) );
		}

	} //namespace utils

} //namespace hude

#endif //__event_bus_lkjjwfejiojoiwef93323290i98u9hy7yf43jifejji2efjnvnjv__
